Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
50.00% |
2 / 4 |
CRAP | |
90.24% |
37 / 41 |
| NotGrantedValuesMerger | |
0.00% |
0 / 1 |
|
50.00% |
2 / 4 |
22.45 | |
90.24% |
37 / 41 |
| __construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| merge | |
0.00% |
0 / 1 |
12.28 | |
87.50% |
21 / 24 |
|||
| getNotGrantedValuesLocalizable | |
100.00% |
1 / 1 |
6 | |
100.00% |
8 / 8 |
|||
| isGrantedAttribute | |
0.00% |
0 / 1 |
3.14 | |
75.00% |
3 / 4 |
|||
| <?php | |
| declare(strict_types=1); | |
| /* | |
| * This file is part of the Akeneo PIM Enterprise Edition. | |
| * | |
| * (c) 2017 Akeneo SAS (http://www.akeneo.com) | |
| * | |
| * For the full copyright and license information, please view the LICENSE | |
| * file that was distributed with this source code. | |
| */ | |
| namespace Akeneo\Pim\Permission\Component\Merger; | |
| use Akeneo\Pim\Enrichment\Component\Product\Factory\ValueCollectionFactoryInterface; | |
| use Akeneo\Pim\Enrichment\Component\Product\Model\EntityWithFamilyVariantInterface; | |
| use Akeneo\Pim\Enrichment\Component\Product\Model\EntityWithValuesInterface; | |
| use Akeneo\Pim\Permission\Component\Attributes; | |
| use Akeneo\Pim\Permission\Component\NotGrantedDataMergerInterface; | |
| use Akeneo\Tool\Component\StorageUtils\Exception\InvalidObjectException; | |
| use Akeneo\Tool\Component\StorageUtils\Repository\IdentifiableObjectRepositoryInterface; | |
| use Doctrine\Common\Util\ClassUtils; | |
| use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; | |
| /** | |
| * Merge not granted values with new values. Example: | |
| * In database, your product "my_product" contains those values: | |
| * { | |
| * "values": { | |
| * "a_text": [ | |
| * { "data": "my text", "locale": null, "scope": null } | |
| * ], | |
| * "a_number": [ | |
| * { "data": 12, "locale": null, "scope": null } | |
| * ], | |
| * "a_localizable_text": [ | |
| * { "data": "my text", "locale": "en_US", "scope": null }, | |
| * { "data": "mon text", "locale": "fr_FR", "scope": null } | |
| * ] | |
| * } | |
| * } | |
| * | |
| * But "a_text" belongs to an attribute group not viewable and locale "fr_FR" is not viewable by the connected user. | |
| * That's means when he will get the product "my_product", the application will return: | |
| * { | |
| * "values": { | |
| * "a_number": [ | |
| * { "data": 12, "locale": null, "scope": null } | |
| * ], | |
| * "a_localizable_text": [ | |
| * { "data": "my text", "locale": "en_US", "scope": null } | |
| * ] | |
| * } | |
| * } | |
| * (@see \Akeneo\Pim\Permission\Component\Factory\ValueCollectionFactory) | |
| * | |
| * When user will update "my_product": | |
| * { | |
| * "values": { | |
| * "a_localizable_text": [ | |
| * { "data": "my english text", "locale": "en_US", "scope": null } | |
| * ] | |
| * } | |
| * } | |
| * | |
| * We have to merge not granted data (here "a_text" value and "a_localizable_text" with locale "fr_FR") before saving data in database. | |
| * Finally, "my_product" will contain: | |
| * { | |
| * "values": { | |
| * "a_text": [ | |
| * { "data": "my text", "locale": null, "scope": null } | |
| * ], | |
| * "a_number": [ | |
| * { "data": 12, "locale": null, "scope": null } | |
| * ], | |
| * "a_localizable_text": [ | |
| * { "data": "my english text", "locale": "en_US", "scope": null }, | |
| * { "data": "mon text", "locale": "fr_FR", "scope": null } | |
| * ] | |
| * } | |
| * } | |
| * | |
| * @author Marie Bochu <marie.bochu@akeneo.com> | |
| */ | |
| class NotGrantedValuesMerger implements NotGrantedDataMergerInterface | |
| { | |
| /** @var AuthorizationCheckerInterface */ | |
| private $authorizationChecker; | |
| /** @var IdentifiableObjectRepositoryInterface */ | |
| private $attributeRepository; | |
| /** @var IdentifiableObjectRepositoryInterface */ | |
| private $localeRepository; | |
| /** @var ValueCollectionFactoryInterface */ | |
| private $valueCollectionFactory; | |
| /** | |
| * @param AuthorizationCheckerInterface $authorizationChecker | |
| * @param IdentifiableObjectRepositoryInterface $attributeRepository | |
| * @param IdentifiableObjectRepositoryInterface $localeRepository | |
| * @param ValueCollectionFactoryInterface $valueCollectionFactory | |
| */ | |
| public function __construct( | |
| AuthorizationCheckerInterface $authorizationChecker, | |
| IdentifiableObjectRepositoryInterface $attributeRepository, | |
| IdentifiableObjectRepositoryInterface $localeRepository, | |
| ValueCollectionFactoryInterface $valueCollectionFactory | |
| ) { | |
| $this->authorizationChecker = $authorizationChecker; | |
| $this->attributeRepository = $attributeRepository; | |
| $this->localeRepository = $localeRepository; | |
| $this->valueCollectionFactory = $valueCollectionFactory; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function merge($filteredEntityWithValues, $fullEntityWithValues = null) | |
| { | |
| if (!$filteredEntityWithValues instanceof EntityWithValuesInterface) { | |
| throw InvalidObjectException::objectExpected(ClassUtils::getClass($filteredEntityWithValues), EntityWithValuesInterface::class); | |
| } | |
| if (null === $fullEntityWithValues) { | |
| return $filteredEntityWithValues; | |
| } | |
| if (!$fullEntityWithValues instanceof EntityWithValuesInterface) { | |
| throw InvalidObjectException::objectExpected(ClassUtils::getClass($fullEntityWithValues), EntityWithValuesInterface::class); | |
| } | |
| $rawValuesToMerge = []; | |
| foreach ($fullEntityWithValues->getRawValues() as $attributeCode => $values) { | |
| $isGrantedAttribute = $this->isGrantedAttribute($attributeCode); | |
| if (null !== $isGrantedAttribute && false === $isGrantedAttribute) { | |
| $rawValuesToMerge[$attributeCode] = $values; | |
| } else { | |
| $notGrantedValuesLocalizable = $this->getNotGrantedValuesLocalizable($values); | |
| if (!empty($notGrantedValuesLocalizable)) { | |
| $rawValuesToMerge[$attributeCode] = $notGrantedValuesLocalizable; | |
| } | |
| } | |
| } | |
| if ($filteredEntityWithValues instanceof EntityWithFamilyVariantInterface && | |
| null !== $filteredEntityWithValues->getFamilyVariant() | |
| ) { | |
| $values = clone $filteredEntityWithValues->getValuesForVariation(); | |
| } else { | |
| $values = clone $filteredEntityWithValues->getValues(); | |
| } | |
| $fullEntityWithValues->setValues($values); | |
| if (!empty($rawValuesToMerge)) { | |
| $notGrantedValues = $this->valueCollectionFactory->createFromStorageFormat($rawValuesToMerge); | |
| foreach ($notGrantedValues as $notGrantedValue) { | |
| $fullEntityWithValues->addValue($notGrantedValue); | |
| } | |
| } | |
| return $fullEntityWithValues; | |
| } | |
| /** | |
| * @param array $values | |
| * | |
| * @return array | |
| */ | |
| private function getNotGrantedValuesLocalizable(array $values): array | |
| { | |
| $notGrantedValues = []; | |
| foreach ($values as $channelCode => $localeRawValue) { | |
| foreach ($localeRawValue as $localeCode => $data) { | |
| if ('<all_locales>' !== $localeCode) { | |
| $locale = $this->localeRepository->findOneByIdentifier($localeCode); | |
| if (null !== $locale && !$this->authorizationChecker->isGranted(Attributes::VIEW_ITEMS, $locale)) { | |
| $notGrantedValues[$channelCode][$localeCode] = $data; | |
| } | |
| } | |
| } | |
| } | |
| return $notGrantedValues; | |
| } | |
| /** | |
| * @param mixed $attributeCode | |
| * | |
| * @return bool|null | |
| */ | |
| private function isGrantedAttribute($attributeCode): ?bool | |
| { | |
| $attribute = $this->attributeRepository->findOneByIdentifier($attributeCode); | |
| if (null === $attribute) { | |
| return null; | |
| } | |
| return $this->authorizationChecker->isGranted(Attributes::VIEW_ATTRIBUTES, $attribute); | |
| } | |
| } |